// 实现使用函数调用MessageMain组件的逻辑
//   引入 创建虚拟节点 和渲染方法
import {ComponentInternalInstance, createVNode, ref, render, shallowReactive, shallowRef, VNode} from 'vue'
// 引入信息提示组件
import MessageMain from './message.vue'
import {MessageOptionsType, MessageProps, MessageStatus, Mutable} from "./types.ts";
import {MessageHandler} from "element-plus";
import {isBoolean, isElement, isNumber, isString} from "lodash-unified";
import messageConfig from "./messageConfig.ts";

// 准备dom容器
const div = document.createElement('div')
// 添加类名
div.setAttribute('class', 'message-container')
// 添加到body上
document.body.appendChild(div)

// 定时器标识
let timer = null

export default ({type, text}) => {
    // 实现：根据MessageMain.vue渲染消息提示
    // 1. 导入组件
    // 2. 根据组件创建虚拟节点   第一个参数为要创建的虚拟节点  第二个参数为props的参数
    const vnode = createVNode(MessageMain, {type, text})
    // 3. 准备一个DOM容器
    // 4. 把虚拟节点渲染DOM容器中
    render(vnode, div)
    // 5. 开启定时器，移出DOM容器内容
    clearTimeout(timer)
    timer = setTimeout(() => {
        render(null, div)
    }, 2000)
}


// 消息展示时间
const MSG_SHOW_TIME = 3000
// 最多展示多少个消息
const MAX_SHOW_MESSAGE = 3
// 消息之间的间距
const MSG_GAP = 10;
const BASE_MSG_JU = 16

// 消息队列
export const messageList = ref([])
let count = 0

function dequeueNextMessage() {
    // 找到下一个 InQueue 的消息
    const nextMessage = messageList.value.find(
        (msg) => msg.status === MessageStatus.InQueue
    )
    if (nextMessage) {
        nextMessage.show()
    }
}

const defineMessageOptions = {
    time: 3000, // 展示时间
    showClose: false, // 是否展示关闭按钮
    type: 'info'
}

export function createOptions(options: any) {
    const normalized = {
        ...defineMessageOptions,
        ...options
    }

    if (!normalized.appendTo) {
        normalized.appendTo = document.body
    } else if (isString(normalized.appendTo)) {
        let appendToEle = document.querySelector(normalized.appendTo)
        if (!isElement(appendToEle)) {
            console.warn(
                "the appendTo option is not HTMLElement. Falling back to document.body."
            )
            appendToEle = document.body
        }
        normalized.appendTo = appendToEle
    }

    // other option setting
    if (isBoolean(messageConfig.grouping) && !normalized.grouping) {
        normalized.grouping = messageConfig.grouping
    }
    if (isNumber(messageConfig.duration) && normalized.duration === 3000) {
        normalized.duration = messageConfig.duration
    }
    if (isNumber(messageConfig.offset) && normalized.offset === 16) {
        normalized.offset = messageConfig.offset
    }
    if (isBoolean(messageConfig.showClose) && !normalized.showClose) {
        normalized.showClose = messageConfig.showClose
    }

    return normalized
}


/**
 * 定义消息上下文
 */
export type MessageContext = {
    id: string,
    vnode: VNode, // 虚拟节点
    handler: MessageHandler,
    vm: ComponentInternalInstance,
    props: Mutable<MessageProps>
}

// 浅层级的响应式
export const instances: MessageContext[] = shallowReactive([])


/**
 * 创建一个 message 消息
 * @param text 要展示的文本
 * @param options 配置
 */
export function useMessageApi(text: string, options: MessageOptionsType = {}) {
    // 1. 对 text 和 options 进行分析生成 message
    const _options = createOptions(options)
    const message = {
        text: text,
        status: ref(MessageStatus.InQueue),
        offsetTop: 0,
        height: 0, // 新增字段：用于保存组件实际高度
        el: (() => {
            // 创建独立的 DOM 容器
            const msgDiv = document.createElement('div');
            msgDiv.className = 'message-item'; // 可选类名
            div.appendChild(msgDiv); // 添加到主容器下
            return msgDiv
        })(),
        removeEl: () => {
            div.removeChild(this.el)
        },
        options: _options,
        show() {
            message.status.value = MessageStatus.Displaying

            // 计算偏移量
            let offset = BASE_MSG_JU;
            messageList.value.forEach(msg => {
                if (msg !== message && msg.status === MessageStatus.Displaying) {
                    offset += msg.height + MSG_GAP;
                }
            });

            message.offsetTop = offset;

            const props = {
                type: message.options.type,
                text: message.text,
                status: message.status,
                offsetTop: message.offsetTop
            }

            const vNode = createVNode(MessageMain, props)

            render(vNode, message.el)


            setTimeout(() => {
                const msgDiv = message.el
                // 关闭逻辑
                render(null, msgDiv);
                div.removeChild(msgDiv); // 移除当前消息容器
                message.status = null;
                message.el = null;
            }, message.options.time)
        }
    }
    messageList.value.push(message);

    message.show()
}
